package com.zrrd.mcl.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.zrrd.mcl.common.result.Result;
import com.zrrd.mcl.common.result.ResultCodeEnum;
import com.zrrd.mcl.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
public class AuthGlobalFliter implements GlobalFilter {

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${authUrls.url}")
    private String authUrls;

    //路径匹配的工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求对象和响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //2.获取当前请求地址
        String path = request.getURI().getPath();
        System.out.println("当前请求地址====>" + path);
        //3.如果请求地址中有inner 代表是内部请求（feign）外部不允许访问
        if (antPathMatcher.match("/**/inner/**", path)) {
            //4.响应结果
            return this.out(response, ResultCodeEnum.PERMISSION);
        }
        //5.获取用户ID
        String userId = this.getUserId(request);
        System.out.println("网关服务获取用户ID====>" + userId);

        //6.token是否被盗用
        if ("-1".equals(userId)) {
            //7.响应结果
            return this.out(response, ResultCodeEnum.PERMISSION);
        }

        //8.用户登录认证--> api请求 (必须要登录)
        if (antPathMatcher.match("/api/**/auth/**", path)) {
            if (StringUtils.isEmpty(userId)) {
                //9.响应结果
                return this.out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //10.url判断(判断当前访问的地址 是否需要登录)
        for (String authUrl : authUrls.split(",")) {
            if (path.indexOf(authUrl) != -1 && StringUtils.isEmpty(userId)) {
                //通过响应对象重定向到登录页面
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION, "http://www.gmall.com/login.html?originUrl=" + request.getURI());
                return response.setComplete();
            }
        }

        //11.获取临时用户ID
        String userTempId = this.getUserTempId(request);
        System.out.println("临时用户ID=====>"+userTempId);
        System.out.println("正式用户ID=====>"+userId);
        //12.将临时用户ID和登录的用户iD其中一个传递给后面的请求
        if(!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)){
            if (!StringUtils.isEmpty(userId)) {
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)) {
                request.mutate().header("userTempId", userTempId).build();
            }
            //放行
            return chain.filter(exchange.mutate().request(request).build());
        }
        return chain.filter(exchange);
    }

    //获取用户ID的方法
    private String getUserId(ServerHttpRequest request) {
        String token = "";
        List<String> tokenList = request.getHeaders().get("token");
        if (tokenList != null && tokenList.size() > 0) {
            token = tokenList.get(0);
        } else {
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            HttpCookie cookie = cookies.getFirst("token");
            if (cookie != null) {
                token = URLDecoder.decode(cookie.getValue());
            }
        }
        if (!StringUtils.isEmpty(token)) {
            String userStr = (String) redisTemplate.opsForValue().get("user:login:" + token);
            if (!StringUtils.isEmpty(userStr)) {
                JSONObject userJson = JSONObject.parseObject(userStr);
                String ip = userJson.getString("ip");
                String currentIp = IpUtil.getGatwayIpAddress(request);
                if (ip.equals(currentIp)) {
                    return userJson.getString("userId");
                } else {
                    return "-1";
                }
            }
        }
        return "";
    }

    //获取临时用户ID的方法
    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = "";
        List<String> tokenList = request.getHeaders().get("userTempId");
        if (tokenList != null ){
            userTempId = tokenList.get(0);
        }else{
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();
            HttpCookie cookie = cookies.getFirst("userTempId");
            if(cookie != null){
                userTempId = URLDecoder.decode(cookie.getValue());
            }
        }
        return userTempId;
    }

    //返回响应信息的方法
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum codeEnum) {
        Result<Object> result = Result.build(null, codeEnum);
        byte[] bytes = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(wrap));
    }
}
